package com.lfxfs.soap.utils;

import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import java.io.*;

/**
 * 封装了XML转换成object，object转换成XML的代码
 *
 * @author Steven
 *
 */
public class XmlUtils {
    /**
     * 将对象直接转换成String类型的 XML输出
     *
     * @param obj
     * @return
     */
    public static String convertToXml(Object obj) {
        // 创建输出流
        StringWriter sw = new StringWriter();
        try {
            // 利用jdk中自带的转换类实现
            JAXBContext context = JAXBContext.newInstance(obj.getClass());

            Marshaller marshaller = context.createMarshaller();
            // 格式化xml输出的格式
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            //设置编码（默认编码就是utf-8）
            marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
            //是否省略xml头信息，默认不省略（false）
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
            // 将对象转换成输出流形式的xml
            marshaller.marshal(obj, sw);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return sw.toString();
    }

    public static Document converToDocument(Object object){
        Document document = null;
        try {
            // 利用jdk中自带的转换类实现
            JAXBContext context = JAXBContext.newInstance(object.getClass());

            document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
            Marshaller marshaller = context.createMarshaller();
            // 格式化xml输出的格式
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            marshaller.marshal(object, document);
        } catch (JAXBException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
        return document;
    }

    /**
     * 将对象根据路径转换成xml文件
     *
     * @param obj
     * @param path
     * @return
     */
    public static void convertToXml(Object obj, String path) {
        try {
            // 利用jdk中自带的转换类实现
            JAXBContext context = JAXBContext.newInstance(obj.getClass());

            Marshaller marshaller = context.createMarshaller();
            // 格式化xml输出的格式
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            //设置编码（默认编码就是utf-8）
            marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
            //是否省略xml头信息，默认不省略（false）
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
            // 将对象转换成输出流形式的xml
            // 创建输出流
            FileWriter fw = null;
            try {
                fw = new FileWriter(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            marshaller.marshal(obj, fw);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("unchecked")
    /**
     * 将String类型的xml转换成对象
     */
    public static Object convertXmlStrToObject(Class clazz, String xmlStr) {
        Object xmlObject = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            // 进行将Xml转成对象的核心接口
            Unmarshaller unmarshaller = context.createUnmarshaller();
            StringReader sr = new StringReader(xmlStr);
            xmlObject = unmarshaller.unmarshal(sr);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xmlObject;
    }

    @SuppressWarnings("unchecked")
    /**
     * 将file类型的xml转换成对象
     */
    public static Object convertXmlFileToObject(Class clazz, String xmlPath) {
        Object xmlObject = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            FileReader fr = null;
            try {
                fr = new FileReader(xmlPath);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            xmlObject = unmarshaller.unmarshal(fr);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xmlObject;
    }

    /**
     * @Description bean转成xml
     * @Param [t]
     * @Return java.lang.String
     */
    public static <T> String beanToXml(T t) {
        String xml=null;
        try {
            //获得 JAXBContext 类的新实例。参数为类的地址
            JAXBContext context = JAXBContext.newInstance(t.getClass());
            //创建一个可以用来将 java 内容树转换为 XML 数据的 Marshaller 对象。
            Marshaller m = context.createMarshaller();
            // 格式化xml输出的格式
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            //设置编码（默认编码就是utf-8）
            m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
            //是否省略xml头信息，默认不省略（false）
            m.setProperty(Marshaller.JAXB_FRAGMENT, true);
            //创建一个StringWriter流将接收到的对象流写入xml字符串
            StringWriter sw = new StringWriter();
            //调用marshal方法进行转换
            m.marshal(t,sw);
            //将读取到的StringWriter流转成String返回
            xml = sw.toString();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xml;
    }

    /**
     * @Description bean转成xml(泛型使用)
     * @Param [t]
     * @Return java.lang.String
     */
    public static <T> String beanToXml(T t, Class c) {
        String xml=null;
        try {
            //获得 JAXBContext 类的新实例。参数为类的地址
            JAXBContext context = JAXBContext.newInstance(t.getClass(),c);
            //创建一个可以用来将 java 内容树转换为 XML 数据的 Marshaller 对象。
            Marshaller m = context.createMarshaller();
            // 格式化xml输出的格式
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            //设置编码（默认编码就是utf-8）
            m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
            //是否省略xml头信息，默认不省略（false）
            m.setProperty(Marshaller.JAXB_FRAGMENT, true);
            //创建一个StringWriter流将接收到的对象流写入xml字符串
            StringWriter sw = new StringWriter();
            //调用marshal方法进行转换
            m.marshal(t,sw);
            //将读取到的StringWriter流转成String返回
            xml= sw.toString();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xml;
    }

    /**
     * @Description xml 转成 bean
     * @Param [xml, t]
     * @Return T
     */
    public static <T> T xmlToBean(String xml, Class<T> t) {
        try {
            ////获得 JAXBContext 类的新实例。参数为类的地址
            JAXBContext context = JAXBContext.newInstance(t);
            //创建一个可以用来将 XML 数据转换为 java 内容树的 Unmarshaller 对象。
            Unmarshaller um = context.createUnmarshaller();
            //创建一个StringReader将xml报文转成流-忽略命名空间，否则会解析出来的值为空
            StringReader sr = new StringReader(xml);
            SAXParserFactory sax = SAXParserFactory.newInstance();
            sax.setNamespaceAware(false);
            XMLReader xmlReader = sax.newSAXParser().getXMLReader();
            Source source = new SAXSource(xmlReader, new InputSource(sr));
            //调用unmarshal进行转换，并把Object类型强转为调用者的类型
            return  (T) um.unmarshal(source);

        } catch (JAXBException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
        //将对象返回给调用者
        return null;
    }

    /**
     * @Description xml 转成 bean(泛型使用)
     * @Param [xml, t]
     * @Return T
     */
    public static <T> T xmlToBean(String xml, T t, Class c) {
        try {
            ////获得 JAXBContext 类的新实例。参数为类的地址
            JAXBContext context = JAXBContext.newInstance(t.getClass(),c);
            //创建一个可以用来将 XML 数据转换为 java 内容树的 Unmarshaller 对象。
            Unmarshaller um = context.createUnmarshaller();
            //创建一个StringReader将xml报文转成流
            StringReader sr = new StringReader(xml);
            //调用unmarshal进行转换，并把Object类型强转为调用者的类型
            t = (T) um.unmarshal(sr);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        //将对象返回给调用者
        return t;
    }



}